package syntaxAnalysis.core;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;

import lexicalAnalysis.core.LexicalAnalyzer;
import lexicalAnalysis.core.Token;

/**
 * 使用表驱动的预测分析法
 * @author 131250050 张鹏
 *
 */

public class SyntaxAnalyzer {
	private CFG cfg;
	private Token[] tokens;
	private PredicateParsingTable table;
	Stack<String> prStack;
	
	public SyntaxAnalyzer(String fileInput) {
		setCFG(System.getProperty("user.dir")+"/src/syntaxAnalysis/CFG");
		LexicalAnalyzer lex=new LexicalAnalyzer(fileInput);
		List<Token> tokenList=lex.getTokens();
		tokens=tokenList.toArray(new Token[tokenList.size()]);
		generatePredicateParsingTable();
		printPredicateParsingTable();
		prStack=new Stack<>();
	}
	
	
	public void begin(){
		System.out.println("");
		System.out.println("start:");
		int i=0;
		prStack.push("$");
		prStack.push("E");
		String top=prStack.peek();
		while(!top.equals("$")){
			String input=getNextToken(i);
			if(top.equals(input)){
				prStack.pop();
				i++;
			}else if(table.get(top, input)==null){
				error(input);
				break;
			}else{
				String production=table.get(top, input);
				System.out.println(production);
				prStack.pop();
				String[] symbols=toSymbol(production);
				for(int j=symbols.length-1;j>-1;j--){
					prStack.push(symbols[j]);
				}
			}
			top=prStack.peek();
		}
	}

	/**
	 * generate predicate parsing table
	 */
	private void generatePredicateParsingTable(){
		table=new PredicateParsingTable();
		Production[] p=cfg.getProductions();
		for(Production pr:p){
			Set<String> prFirst=cfg.first(pr);
			if(prFirst.contains("0")){
				prFirst.remove("0");
				Set<String> prFollow=cfg.follow(pr.getLeft());
				for(String aFollowValue:prFollow){
					table.set(pr.getLeft(), aFollowValue, pr.toString());
				}
			}
			for(String aFirstValue:prFirst){
				table.set(pr.getLeft(), aFirstValue, pr.toString());
			}
		}
	}
	
	public void printPredicateParsingTable(){
		System.out.println("Predicate Parsing Table:");
		System.out.println();
		table.print();
		System.out.println();
	}
	
	

	private String getNextToken(int i){
		if(i==tokens.length){
			return "$";
		}
		return tokens[i].toString();
		
	}


	private void setCFG(String cfgFilePath){
		 List<Production> cfgs=new LinkedList<>();
		 try {
			Scanner scanner=new Scanner((new File(cfgFilePath)));
			while(scanner.hasNextLine()){
				String current=scanner.nextLine();
				String[] leftAndRight=current.split("->");
				if(leftAndRight.length==2)
					cfgs.add(new Production(leftAndRight[0],leftAndRight[1]));
			}
			scanner.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		cfg=new CFG((Production[]) cfgs.toArray(new Production[cfgs.size()]));
	}

	private void error(String msg){
		System.out.println("error on "+msg);
	}
	
	private String[] toSymbol(String production){
		String[] result;
		String right=production.substring(production.indexOf("->")+2);
		if(right.contains("id")){
			return new String[]{"id"};
		}else if(right.equals("0")){
			result=new String[]{};
		}else{
			char[] symbols=right.toCharArray();
			result=new String[symbols.length];
			for(int i=0;i<symbols.length;i++){
				result[i]=String.valueOf(symbols[i]);
			}
		}
		return result;
	}
	
}
